%%--------------------------------------------------------------------
%%
%% %CopyrightBegin%
%%
%% SPDX-License-Identifier: Apache-2.0
%%
%% Copyright Ericsson AB 2010-2025. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%%     http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
%%-----------------------------------------------------------------
%% File: otp_man_index.erl
%% 
%% Description:
%%    This file generates the module overview in the documentation.
%%
%%-----------------------------------------------------------------

-module(otp_man_index). 

-include_lib("kernel/include/eep48.hrl").

-export([gen/1]).

gen([OutFile])  when is_atom(OutFile) ->
    try
        Data = [header(), "\n\n", module_table(), "\n\n", footer()],
        ok = file:write_file(atom_to_list(OutFile), Data)
    catch E:R:ST ->
            io:format("~p",[{E,R,ST}]),
            exit(1)
    end,
    ok.

header() ->
    "# Module Index\n".

module_table() ->
    Modules =
        lists:filtermap(
          fun({M, Path, _Loaded}) ->
                  case code:get_doc(list_to_atom(M),#{ sources => [eep48] }) of
                      {ok, #docs_v1{ format = <<"text/markdown">>,
                                     module_doc = #{ <<"en">> := ModuleDoc } }} ->
                          {true, {M, module_path_to_app_vsn(Path),
                                  extract_first_sentence(ModuleDoc)}};
                      {ok, #docs_v1{ format = <<"application/erlang+html">>,
                                     module_doc = #{ <<"en">> := ModuleDoc } }} ->
                          {true, {M, module_path_to_app_vsn(Path),
                                  extract_first_sentence_html(ModuleDoc)}};
                      _ ->
                          false
                  end
          end, code:all_available()),
    ["|  Module name | Description | Application |\n",
     "|--------------|-------------|-------------|\n",
     [["|  `m:", M, "` | ",ModuleDoc," | [", App,"-",Vsn,"](`e:",App,":index.html`) |\n"] ||
         {M, {App,Vsn}, ModuleDoc} <- Modules],
     "\n\n"].

module_path_to_app_vsn(preloaded) ->
    {"erts",erlang:system_info(version)};
module_path_to_app_vsn(Path) ->
    App = case filename:split(string:prefix(Path, os:getenv("ERL_TOP"))) of
              ["/", "lib", AppStr | _] ->
                  list_to_atom(AppStr);
              ["lib", AppStr | _] ->
                  list_to_atom(AppStr);
              ["nomatch"] ->
                  error("ERL_TOP environment variable doesn't match the PATH " ++ Path)
          end,
    case application:load(App) of
        ok -> ok;
        {error, {already_loaded, App}} -> ok
    end,
    {ok, Vsn} = application:get_key(App, vsn),
    {atom_to_list(App), Vsn}.

extract_first_sentence(Markdown) ->
    [Head | _] = string:lexemes(Markdown, "\n"),
    string:replace([string:trim(Head,trailing,"."),"."], "|", "\\|", all).

extract_first_sentence_html([{p,_,First}|_]) ->
    extract_first_sentence(strip_tags(First)).

strip_tags([H | T]) when is_binary(H) ->
    [H | strip_tags(T)];
strip_tags([{_Tag, _, H} | T]) ->
    [strip_tags(H) | strip_tags(T)];
strip_tags([]) ->
    [].



footer() ->
    io_lib:format("<!-- Generated by ~p -->\n", [?MODULE]).
